package eol.vm;

import java.util.ArrayList;

import util.Assert;

/** The code store holds a set of Segments, indexed by an int segNum
 *  */
class CodeStore {
	/** A segment holds the machine code for one function or
	 * top-level expression. */
	static class Segment {
		ArrayList<Byte> byteCodes = new ArrayList<Byte>() ;

		byte fetch(int addr ) { return byteCodes.get(addr) ; }

		void put( int addr, byte b ) {
			Assert.check(0 <= addr && addr <= byteCodes.size() ) ;
			if( addr == byteCodes.size() ) {
				byteCodes.add(b) ; }
			else {
				byteCodes.set(addr, b) ; } }

		int getSize() {return byteCodes.size() ; }
	}
	
	ArrayList<CodeStore.Segment> segments = new ArrayList<CodeStore.Segment>() ;

	// The index stack is used during code generation.
	// When a function is inside another, we need to leave the
	// current segment to start a new one. This stack
	// keeps track of where we were. The top of this stack
	// is the index of the current segment, i.e. the segment
	// to which new code should be emitted.
	ArrayList<Integer> indexStack = new ArrayList<Integer>() ;

	int size() { return segments.size() ; }

	int startSegment() {
		int segNum = segments.size() ;
		indexStack.add( segNum ) ;
		segments.add( new Segment() ) ;
		return segNum ; }

	void endSegment() {
		indexStack.remove( indexStack.size()-1 ) ; }

	int segmentSize( int segNum ) {
		return segments.get(segNum).getSize() ; }

	byte fetch( int segNum, int addr ) {
		Assert.check( 0 <= addr && addr < segmentSize( segNum) ) ;
		return segments.get( segNum ).fetch( addr ) ; }

	void put(int addr, byte b) { 
		int segNum = getCurrentSegNum() ;
		segments.get(segNum).put( addr, b ) ; }

	int getCurrentSegNum() { return indexStack.get( indexStack.size() - 1 ) ; }

	int getCurrentCodeAddr() { return segmentSize( getCurrentSegNum() ) ; }
}